package gpstools;

import gpstools.math.GeoCalculations;

import java.io.Serializable;

import mskruch.gps.Position;

/**
 * The default implementation for 3D location
 * 
 * @author Marcin Skruch
 */
public class Point implements Location3D, Position, Serializable {
    private static final long serialVersionUID = 1L;
    
    private final double latitude;
    private final double longitude;
	private final Double elevation;

	public Point(double latitude, double longitude, Double elevation)
	{
        super();
        if (latitude > 90 || latitude < -90) {
            throw new IllegalArgumentException("latitude must be between -90 degrees and +90 degrees");
        }
        if (longitude > 180 || longitude < -180) {
            throw new IllegalArgumentException("longitude must be between -180 degrees and +180 degrees");
        }
        this.latitude = latitude;
        this.longitude = longitude;
        this.elevation = elevation;
    }

    public Point(double latitude, double longitude) {
		this(latitude, longitude, null);
    }

    public Point(Location location) {
        this(location.getLatitude(),location.getLongitude());
    }

    public double distanceTo(Location another) {
        return GeoCalculations.distance(this.latitude, this.longitude, another.getLatitude(), another.getLongitude());
    }

    @Override
    public double getLatitude() {
        return latitude;
    }

    @Override
    public double getLongitude() {
        return longitude;
    }

    @Override
	public Double getElevation()
	{
        return elevation;
    }

    @Override
    public String toString() {
        return String.format("(%.6f, %.6f) [%.1f]", latitude, longitude, elevation);
    }

    /* generated */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(elevation);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(latitude);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(longitude);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    /* generated */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Point other = (Point) obj;
        if (Double.doubleToLongBits(elevation) != Double.doubleToLongBits(other.elevation)) {
            return false;
        }
        if (Double.doubleToLongBits(latitude) != Double.doubleToLongBits(other.latitude)) {
            return false;
        }
        if (Double.doubleToLongBits(longitude) != Double.doubleToLongBits(other.longitude)) {
            return false;
        }
        return true;
    }

    @Override
    public double distanceTo(Position anotherPoint) {
        // TODO remove
        return distanceTo((Location)new Point(anotherPoint.getLatitude(), anotherPoint.getLongitude()));
    }
    
}
